package com.sojson.websocket.util;

import com.sojson.util.id.IdUtil;
import com.sojson.util.lock.CustomLock;
import com.sojson.util.lock.LockUtil;
import com.sojson.websocket.util.bean.WebSocketData;
import com.sojson.websocket.util.enums.EWebSocketDataType;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

/**
 * WebSocket数据处理工具类
 *
 * @author liu
 * @date 2024-05-31
 */
@Slf4j
public class WebSocketDataUtil {

    /**
     * 拼包
     *
     * @param ctx
     * @param data
     * @return
     * @throws Exception
     */
    public static void add(ChannelHandlerContext ctx, String data) throws Exception {
        if (data.equals(WebSocketUtil.OTHER_FORTY_ONE)) {
            log.info(new StringBuilder("WebSocket收到其他包,此功能未实现: ").append(data).toString());
            return;
        }

        Channel channel = ctx.channel();

        String key = null;
        Object object = channel.attr(AttributeKey.valueOf(WebSocketPoolUtil.ID_KEY)).get();
        if (object == null) {
            key = IdUtil.uuid();
            channel.attr(AttributeKey.valueOf(WebSocketPoolUtil.ID_KEY)).set(key);
        } else {
            key = object.toString();
        }

        long timeMillis = System.currentTimeMillis();
        CustomLock defaultLock = LockUtil.getLock(key);
        try {
            defaultLock.lock();

            Attribute<Object> dataObj = channel.attr(AttributeKey.valueOf(WebSocketPoolUtil.DATA_KEY));
            Attribute<Object> dataTimeObj = channel.attr(AttributeKey.valueOf(WebSocketPoolUtil.DATA_TIME_KEY));
            if (dataObj == null || dataObj.get() == null || dataTimeObj == null || dataTimeObj.get() == null
                || timeMillis - Long.parseLong(dataTimeObj.get().toString()) > 1000 * 60) {
                dataObj.set(data);
            } else {
                data = dataObj.get().toString() + data;
                dataObj.set(data);
            }
            dataTimeObj.set(timeMillis);
        } finally {
            defaultLock.unlock();
        }
    }

    /**
     * 拆包
     *
     * @param ctx
     * @return
     * @throws Exception
     */
    public static WebSocketData get(ChannelHandlerContext ctx) throws Exception {
        String datas = null;
        WebSocketData WebSocketData = new WebSocketData();
        Channel channel = ctx.channel();

        String key = channel.attr(AttributeKey.valueOf(WebSocketPoolUtil.ID_KEY)).get().toString();
        CustomLock defaultLock = LockUtil.getLock(key);
        try {
            defaultLock.lock();

            Attribute<Object> attr = channel.attr(AttributeKey.valueOf(WebSocketPoolUtil.DATA_KEY));
            datas = attr.get().toString();
            // 分类处理
            if (datas.startsWith(WebSocketUtil.HARVESTER)) {
                // 485电表
                attr.set(datas.substring(40));
                WebSocketData.setType(EWebSocketDataType.HEARTBEAT_485);
                WebSocketData.setData(datas.substring(0, 40));
                return WebSocketData;
            } else {
                // 4G电表
                if (datas.startsWith(WebSocketUtil.HEAD_REGISTER)) {
                    // 注册包
                    attr.set(datas.substring(102));
                    WebSocketData.setType(EWebSocketDataType.REGISTER);
                    WebSocketData.setData(datas.substring(0, 102));
                    return WebSocketData;
                } else if (datas.startsWith(WebSocketUtil.HEAD_HEARTBEAT)) {
                    // 心跳包
                    attr.set(datas.substring(172));
                    WebSocketData.setType(EWebSocketDataType.HEARTBEAT);
                    WebSocketData.setData(datas.substring(0, 172));
                    return WebSocketData;
                } else if (datas.startsWith(WebSocketUtil.HEAD_BUSINESS)) {
                    // 业务包
                    int index = 24 + Integer.parseInt(datas.substring(18, 20), 16) * 2;
                    attr.set(datas.substring(index));
                    WebSocketData.setType(EWebSocketDataType.BUSINESS);
                    WebSocketData.setData(datas.substring(0, index));
                    return WebSocketData;
                } else if (datas.length() == 0) {
                    return null;
                } else {
                    if (datas.contains(WebSocketUtil.HEAD_REGISTER) || datas.contains(WebSocketUtil.HEAD_HEARTBEAT)
                        || datas.contains(WebSocketUtil.HEAD_BUSINESS)) {
                        int indexOfRegister = datas.indexOf(WebSocketUtil.HEAD_BUSINESS);
                        int indexOfHeartbeat = datas.indexOf(WebSocketUtil.HEAD_BUSINESS);
                        int indexOfBusiness = datas.indexOf(WebSocketUtil.HEAD_BUSINESS);
                        if (indexOfRegister > indexOfHeartbeat) {
                            indexOfRegister = indexOfHeartbeat;
                        }
                        if (indexOfRegister > indexOfBusiness) {
                            indexOfRegister = indexOfBusiness;
                        }
                        attr.set(datas.substring(indexOfRegister));
                        log.info(new StringBuilder("WebSocket收到其他包,此功能未实现: ")
                            .append(datas.substring(0, indexOfRegister)).toString());
                        WebSocketData.setType(EWebSocketDataType.OTHER);
                        return WebSocketData;
                    } else {
                        log.info(new StringBuilder("WebSocket收到半包,等待下次补包: ").append(datas).toString());
                        return null;
                    }
                }
            }
        } catch (StringIndexOutOfBoundsException e) {
            log.info(new StringBuilder("WebSocket收到半包,等待下次补包: ").append(datas).append(",").append(e.getMessage())
                .toString());
            return null;
        } finally {
            defaultLock.unlock();
        }
    }

}